﻿#region Disclaimer / License
// Copyright (C) 2011, Kenneth Bergeron, IAP Worldwide Services, Inc
// NOAA :: National Marine Fisheries Service
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
// 
#endregion
using System;
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
using System.Data;

namespace DataSets
{
    public partial class LocalDataSet
    {
        public static string DefaultXMLFile
        {
            get { return DataSets.Glob.DefaultFilePath("Catch.XML"); }
        }
        public Exception Load()
        {
            return Load(DefaultXMLFile);
        }
        public Exception Load(string aFile)
        {
            if (!System.IO.File.Exists(aFile)) return new Exception("File " + aFile + ": Not found.");
            Exception Result = null;
            try
            {
                this.Clear();
                this.ReadXml(aFile);
            }
            catch (Exception Ex)
            {
                Result = Ex;
                Debug.WriteLine(Ex);
            }
            return Result;
        }
        public Exception Save()
        {
            return Save(DefaultXMLFile);
        }
        public Exception Save(string aFile)
        {
            Exception Result = null;
            try
            {
                this.WriteXml(aFile);
            }
            catch (Exception Ex)
            {
                Result = Ex;
                Debug.WriteLine(Ex);
            }
            return Result;
        }
        private string Quoted(object aValue, Type aType)
        {
            if (aValue == null || aValue == System.Convert.DBNull) return string.Empty;
            if (aType == typeof(string))
                return "\"" + ((string)aValue).Replace("\"", "\\\"") + "\"";
            return aValue.ToString();
        }
        public string ToCSV()
        {
            List<DataColumn> FishCols = 
                this.Fish.Columns.Cast<DataColumn>().ToList();
            var ColNames = FishCols.Select(qC=>qC.ColumnName);
            List<DataColumn> FishSampleCols =
                this.FishSamples.Columns.Cast<DataColumn>()
                                        .Where(qC=>!ColNames.Contains(qC.ColumnName))
                                        .ToList();
            List<string> Result = new List<string>(new string[] { "\"" + string.Join("\",\"", FishCols) + "\"\n" });
            foreach(FishRow Row in this.Fish)
            {
                string FishLine = string.Join(",", FishCols.Select(qC => Quoted(Row[qC], qC.DataType)).ToArray());
                FishSamplesRow[] Samples = Row.GetFishSamplesRows();
                if (Samples.Length == 0)
                    Result.Add(FishLine + new string(',', FishSampleCols.Count+1)); // Add the generic row
                // add each samples row with the fish data attached.
                foreach(FishSamplesRow sRow in Samples)
                    Result.Add(FishLine + "," + string.Join(",", FishSampleCols
                        .Select(qC => Quoted(sRow[qC], qC.DataType)).ToArray()));
            }
            return string.Join("\n", Result);
        }
        public partial class FishSamplesRow
        {
            public enum SampleType
            {
                Sample = 0,
                Measurement = 1,
                Tag = 2
            }
            public SampleType Sample
            {
                get
                {
                    if (this.IsTypeNull() || !System.Enum.IsDefined(typeof(SampleType), this.Type))
                        this.Type = SampleType.Sample.ToString();
                    return (SampleType)System.Enum.Parse(typeof(SampleType), this.Type);
                }
                set { this.Type = value.ToString(); }
            }
            public new string ToString()
            {
                return this.Type + ": " + DataSets.Glob.Support.Describe(this.Type, this.CODE) + "[" + this.CODE + "]" +
                    ": " + (this.Sample == DataSets.LocalDataSet.FishSamplesRow.SampleType.Tag ?
                    "Number " + this.Identifier + " " + (this.Retrieved ? "Retrieved" : "Deployed") :
                    this.Value.ToString("G")) + ": " + this.Description +":" +this.Identifier+":"+this.Comment;
            }
        }
        public partial class FishDataTable
        {
            public System.Data.DataRelation FishToFishSamples
            {
                get { return this.ChildRelations["Fish_FishSamples"]; }
            }
        }
        public partial class FishSamplesDataTable
        {
            public FishSamplesRow NewFishSamplesRow(string aStation, int aHookId)
            {
                FishSamplesRow Result = NewFishSamplesRow();
                Result.Station = aStation;
                Result.HookID = aHookId;
                Result.CODE = string.Empty;
                Result.Description = string.Empty;
                Result.Retrieved = false;
                Result.Type = string.Empty;
                Result.Value = 0d;
                return Result;
            }
        }
        public partial class FishRow
        {
            public FishSamplesRow NewFishSamplesRow()
            {
                return ((FishSamplesDataTable)this.tableFish.ChildRelations[0].ChildTable).NewFishSamplesRow(this.Station, this.HookID);
            }
            public void AddFishSamplesRow(FishSamplesRow aRow)
            {
                ((FishSamplesDataTable)this.tableFish.ChildRelations[0].ChildTable).AddFishSamplesRow(aRow);
            }
            public int Aux { get { return this.GetFishSamplesRows().Length; } }
            public string VesselName
            {
                get
                {
                    if (this.IsVesselCodeNull() || string.IsNullOrEmpty(this.VesselCode)) return string.Empty;
                    return Glob.Support.VesselName(this.VesselCode);
                }
                set
                {
                    this.VesselCode = Glob.Support.VesselCode(value);
                }
            }
            public enum Mortalities
            {
                Alive=0,
                AliveDamaged=1,
                Dead=2,
                DeadDamaged=3,
                Unknown=4
            }
            private int GetIndex(string aValue, string[] aValues, int aDefault)
            {
                if (string.IsNullOrEmpty(aValue) || aValues == null || aValues.Length == 0) return aDefault;
                int ix = Array.IndexOf(aValues, aValue);
                if (ix < 0) ix = Array.IndexOf(aValues, aValue.ToLower());
                if (ix < 0) return aDefault;
                return ix;
            }
            private static string[] MortalityCodes = new string[] { "A", "AD", "D", "DD", "?" };
            private static string[] MortalityNames = new string[] 
                { "alive", "alive damaged", "dead", "dead damaged", "unknown" };
            public string MortalityName
            {
                get { return MortalityNames[(int)this.Mortality]; }
                set { Mortality = (Mortalities)GetIndex(value, MortalityNames, (int)Mortalities.Unknown); }
            }
            public Mortalities Mortality
            {
                get { return (Mortalities)GetIndex(this.MortalityCode, MortalityCodes, (int)Mortalities.Unknown); }
                set { this.MortalityCode = MortalityCodes[(int)value]; }
            }
            public enum Sexes
            {
                Male=0,
                Female=1,
                Unknown=2,
                Skipped=3
            }
            public static string[] SexCodes = new string[] { "M", "F", "U", "S" };
            public static string[] SexNames = new string[] { "male", "female", "unknown", "skipped" };
            public string SexName
            {
                get { return SexNames[(int)Sex]; }
                set { Sex = (Sexes)GetIndex(value, SexNames, (int)Sexes.Unknown); }
            }
            public Sexes Sex
            {
                get { return (Sexes)GetIndex(this.SexCode, SexCodes, (int)Sexes.Unknown); }
                set { this.SexCode = SexCodes[(int)value]; }
            }
            public enum Stages
            {
                Undefined = 0,
                Unknown = 1,
                Resting = 2,
                Developing = 3,
                Ripe = 4,
                Spent = 5,
                Mature = 6,
                Immuture = 7,
                NotTaken = 8,
            }
            public string[] StageNames = new string[]
            {
                "undefined",
                "unknown",
                "resting",
                "developing",
                "ripe",
                "spent",
                "mature",
                "immuture",
                "not taken",
            };
            public string StageName
            {
                get { return StageNames[(int)this.Stage]; }
                set { this.Stage = (Stages)GetIndex(value, StageNames, (int)Stages.Undefined); }
            }
            public Stages Stage
            {
                get
                {
                    int ix = 0; 
                    if (this.IsStageCodeNull() || string.IsNullOrEmpty(this.StageCode)
                        || !int.TryParse(this.StageCode, out ix) || ix < 0 || ix > 8) return Stages.Undefined;
                    return (Stages)ix;
                }
                set { this.StageCode = value.ToString(); }
            }
        }
    }
}